package com.atguigu.gmall.cart.service.impl;

import com.atguigu.gmall.cart.service.CartInfoAsyncService;
import com.atguigu.gmall.cart.service.CartInfoService;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.util.AuthContextHolder;
import com.atguigu.gmall.model.cart.CartInfo;
import com.atguigu.gmall.model.product.SkuInfo;
import com.atguigu.gmall.product.client.ProductFeignClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class CartInfoServiceImpl implements CartInfoService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private CartInfoAsyncService cartInfoAsyncService;

    @Autowired
    private ProductFeignClient productFeignClient;

    //加入购物车
    @Override
    public CartInfo addCart(Long skuId, Integer skuNum) {

        //真实用户id或临时用户id
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        //获取真实用户id
        String userId = AuthContextHolder.getUserId(request);
        if (StringUtils.isEmpty(userId)){
            //真实为空，获取临时用户id
            userId = AuthContextHolder.getUserTempId(request);
        }
        //String userId = "3";//假的，暂时使用

        //1.写Redis缓存 同步写  使用hash类型
        //参数1： h  Map h = new HashMap()
        //参数2： hk h.put(k,)
        //参数3： hv h.put(k,v)
        String cacheH = RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
        String cacheHK = skuId.toString();
        //查询Redis 缓存有追加数量，缓存没有添加缓存
        CartInfo cartInfo = (CartInfo) redisTemplate.opsForHash().get(cacheH,cacheHK);
        if (null != cartInfo){
            //缓存中已存在，追加商品数量
            cartInfo.setSkuNum(cartInfo.getSkuNum() + skuNum);
            //选中商品
            cartInfo.setIsChecked(1);

            //2.写MySQL缓存 异步写  保存购物车信息（主要作用是备份） 修改
            cartInfoAsyncService.updateByIdAsync(cartInfo);
        }else {
            //缓存中没有，直接作为新商品添加
            cartInfo = new CartInfo();
            //商品id
            cartInfo.setSkuId(skuId);
            //商品数量
            cartInfo.setSkuNum(skuNum);
            //库存信息对象
            SkuInfo skuInfo = productFeignClient.getSkuInfo(skuId);
            cartInfo.setUserId(userId);
            //购物车价格
            cartInfo.setCartPrice(skuInfo.getPrice());
            //图片
            cartInfo.setImgUrl(skuInfo.getSkuDefaultImg());
            //名称
            cartInfo.setSkuName(skuInfo.getSkuName());
            //实时价格
            cartInfo.setSkuPrice(skuInfo.getPrice());

            //2.写MySQL缓存 异步写  保存购物车信息（主要作用是备份） 添加
            cartInfoAsyncService.insertAsync(cartInfo);
        }
        System.out.println("主线程:" + Thread.currentThread().getName());
        //保存到Redis中
        redisTemplate.opsForHash().put(cacheH,cacheHK,cartInfo);

        //可以设置过期时间，本次就不设置了

        return cartInfo;
    }

    //查询新加入购物车的商品
    @Override
    public CartInfo toCart(Long skuId) {
        //String userId = "3";//假的，暂时使用
        //真实用户id或临时用户id
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        //获取真实用户id
        String userId = AuthContextHolder.getUserId(request);
        if (StringUtils.isEmpty(userId)){
            //真实为空，获取临时用户id
            userId = AuthContextHolder.getUserTempId(request);
        }
        String cacheH = RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
        String cacheHK = skuId.toString();
        return (CartInfo) redisTemplate.opsForHash().get(cacheH,cacheHK);
    }

    //查询当前用户的购物车集合（临时或真实或真实+临时）
    @Override
    public List<CartInfo> cartList(String userId, String userTempId) {
        //判断
        if (!StringUtils.isEmpty(userId)) {
            //有真实用户
            if (!StringUtils.isEmpty(userTempId)) {
                //有临时用户 合并购物车集合再返回
                return mergeCartList(userId,userTempId);
            }else {
                //无临时用户 返回真实用户的购物车集合
                getCartList(userId);
            }
        }else {
            //无真实用户
            if (!StringUtils.isEmpty(userTempId)) {
                //有临时用户 返回临时用户的购物车集合
                return getCartList(userTempId);
            }
        }
        //啥也没有（真实+临时都没有）
        return null;
    }

    //复选框
    @Override
    public void checkCart(Long skuId, Integer isChecked) {
        //真实用户id或临时用户id
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        //获取真实用户id
        String userId = AuthContextHolder.getUserId(request);
        //同步更新缓存
        String cacheH = RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
        String cacheHK = skuId.toString();
        CartInfo cartInfo = (CartInfo) redisTemplate.opsForHash().get(cacheH,cacheHK);
        cartInfo.setIsChecked(isChecked);
        redisTemplate.opsForHash().put(cacheH,cacheHK,cartInfo);
        //异步更新数据库
        cartInfoAsyncService.updateByIdAsync(cartInfo);
    }

    //商品清单
    @Override
    public List<CartInfo> getCartListChecked(String userId) {
        String cacheH = RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
        List<CartInfo> cartInfoList = redisTemplate.opsForHash().values(cacheH);
        //如果加了Cancal就是实时价格了
        return cartInfoList.stream().filter(cartInfo -> cartInfo.getIsChecked() == 1).collect(Collectors.toList());
    }

    //合并购物车集合
    private List<CartInfo> mergeCartList(String userId, String userTempId) {
        //1.获取真实
        List<CartInfo> cartListUserId = getCartList(userId);
        //2.获取临时
        List<CartInfo> cartListUserTempId = getCartList(userTempId);
        //3.判断
        if (!CollectionUtils.isEmpty(cartListUserId)){
            //有：真实用户的购物车集合
            if (!CollectionUtils.isEmpty(cartListUserTempId)){
                //有：临时用户的购物车集合 合并真实+临时用户的购物车（*）
                Map<Long, CartInfo> cartInfoMapUserId = cartListUserId.stream().collect(Collectors
                        .toMap(CartInfo::getSkuId, cartInfo -> cartInfo));

                cartListUserTempId.stream().forEach(cartInfoUserTempId -> {
                    //判断 临时购物车是否在真实购物车中存在
                    CartInfo cartInfoUserId = cartInfoMapUserId.get(cartInfoUserTempId.getSkuId());
                    if (cartInfoUserId != null){
                        //1.存在  追加数量  设置选中
                        cartInfoUserId.setSkuNum(cartInfoUserId.getSkuNum()+cartInfoUserTempId.getSkuNum());
                        cartInfoUserId.setIsChecked(1);
                        //更新Redis
                        String cacheHUserId = RedisConst.USER_KEY_PREFIX + userId +
                                RedisConst.USER_CART_KEY_SUFFIX;
                        redisTemplate.opsForHash().put(cacheHUserId,
                                cartInfoUserId.getSkuId().toString(),cartInfoUserId);
                        //异步更新DB
                        cartInfoAsyncService.updateByIdAsync(cartInfoUserId);

                    } else {
                        //2.不存在 添加新购物车
                        cartInfoMapUserId.put(cartInfoUserTempId.getSkuId(),cartInfoUserTempId);
                        //添加Redis
                        cartInfoUserTempId.setUserId(userId);
                        String cacheHUserId = RedisConst.USER_KEY_PREFIX + userId +
                                RedisConst.USER_CART_KEY_SUFFIX;
                        redisTemplate.opsForHash().put(cacheHUserId,
                                cartInfoUserTempId.getSkuId().toString(),cartInfoUserTempId);

                        //异步添加DB
                        cartInfoAsyncService.insertAsync(cartInfoUserTempId);
                    }
                });
                //删除数据库里临时用户的购物车数据
                cartInfoAsyncService.deleteByUserTempId(userTempId);

                //整体将Redis里的临时用户的购物车删除掉
                String cacheHUserTempId = RedisConst.USER_KEY_PREFIX + userTempId +
                        RedisConst.USER_CART_KEY_SUFFIX;
                redisTemplate.delete(cacheHUserTempId);
                //合并结束  将cartInfoMapUserId（Map）转回List集合
               return new ArrayList(cartInfoMapUserId.values());
            }else {
                //无：临时用户的购物车集合
                return cartListUserId;
            }
        }else {
            //无：真实用户的购物车集合
            if (!CollectionUtils.isEmpty(cartListUserTempId)){
                //有：临时用户的购物车集合
                //真实用户已存在，更新缓存（主）及数据库（异步）
                String cacheHUserTempId = RedisConst.USER_KEY_PREFIX + userTempId +
                        RedisConst.USER_CART_KEY_SUFFIX;
                String cacheHUserId = RedisConst.USER_KEY_PREFIX + userId +
                        RedisConst.USER_CART_KEY_SUFFIX;
                Map<String, CartInfo> cartInfoMap = cartListUserTempId.stream().map(cartInfo -> {
                    //临时用户id改真实用户id
                    cartInfo.setUserId(userId);
                    return cartInfo;
                }).collect(Collectors
                        .toMap(cartInfo -> cartInfo.getSkuId().toString(),
                                cartInfo -> cartInfo));
                //添加真实用户的缓存
                redisTemplate.opsForHash().putAll(cacheHUserId,cartInfoMap);
                //将临时用户的缓存删除掉
                redisTemplate.delete(cacheHUserTempId);
                //开启子线程 更新数据库
                cartInfoAsyncService.updateByIdAsyncExt(userTempId,userId);

                return cartListUserTempId;
            }
        }
        //啥也没有
        return null;
    }

    //返回购物车集合，根据用户id
    private List<CartInfo> getCartList(String userId) {
        String cacheH = RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
        //有可能更新实时价格
        List<CartInfo> cartInfoList = redisTemplate.opsForHash().values(cacheH);
        cartInfoList.forEach(cartInfo -> {
            cartInfo.setSkuPrice(productFeignClient.getPrice(cartInfo.getSkuId()));
        });

        //排序（按时间排序） 作业，添加时间字段（数据库和对象表里）
        //按数量倒序排列
        return cartInfoList.stream().sorted((o1,o2) -> {
            return o2.getSkuNum()-o1.getSkuNum();
        }).collect(Collectors.toList());
    }

    //去购物车结算 再次查询实时价格  页面回显：实时价格
}
